<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
        canvas {
            background-color: green;
            display: block;
            margin: 0 auto;
        }

        .tip {
            text-align: center;
        }
    </style>
</head>

<body>
    <div class="tip">请下棋</div>
</body>

</html>

<script>
    const canvas = document.createElement("canvas");
    canvas.width = 800;
    canvas.height = 800;
    document.body.append(canvas);
    const context = canvas.getContext("2d");

    const tip = document.querySelector(".tip");

    // 画棋盘，棋盘是由横线和纵线组成
    // 循环14次,画出线条
    for (let i = 1; i < 16; i++) {
        // 横线，
        context.moveTo(50, 50 * i);
        context.lineTo(750, 50 * i);
        context.stroke();
        // z纵线
        context.moveTo(50 * i, 50);
        context.lineTo(50 * i, 750);
        context.stroke();
    }

    // 使用二维数组把所有的棋子存起来
    let circles = [];

    for (let i = 0; i < 16; i++) {
        circles[i] = [];
    }

    let isBlack = true;
    let gameEnd = false; //标示是否有人获胜

    // 当点击在棋盘里面的时候，绘制一个圆
    canvas.addEventListener("click", (e) => {
        let { offsetX, offsetY } = e;

        if (offsetX < 25 || offsetY < 25 || offsetX > 775 || offsetY > 775) return;

        let i = Math.floor((offsetX + 25) / 50);
        let j = Math.floor((offsetY + 25) / 50);

        // 判断是否有人获胜
        if (gameEnd) return

        if (circles[i][j]) {
            tip.innerText = `这里不能重复落子，当前是 ${isBlack ? "黑棋" : "白棋"
                }回合`;
            return;
        }

        let x = i * 50;
        let y = j * 50;

        context.beginPath();
        context.arc(x, y, 20, 0, 2 * Math.PI);
        // context.fillStyle = isBlack ? "black " : "white";

        // 把对应的棋子存到二维数组里面
        circles[i][j] = isBlack ? "black" : "white";

        let tx = isBlack ? x - 10 : x + 10;
        let ty = isBlack ? y - 10 : y + 10;
        let g = context.createRadialGradient(tx, ty, 0, tx, ty, 30);

        g.addColorStop(0, isBlack ? "#ccc" : "#666");
        g.addColorStop(1, isBlack ? "#000" : "#fff");
        context.fillStyle = g;

        // 设置阴影美化棋子增加立体感
        context.shadowBlur = 4;
        context.shadowColor = '#333';
        context.shadowOffsetX = 4;
        context.shadowOffsetY = 4;





        context.fill();
        context.closePath();

        gameEnd = checkVertical(i, j) || checkHorizontal(i, j) || checkNW2SE(i, j) || checkNE2SW(i, j)

        if (gameEnd) {
            tip.innerText = `${isBlack ? "黑" : "白"}棋获胜！`
            return;
        }

        tip.innerText = isBlack ? "轮到白棋了!" : "轮到黑棋了！";

        isBlack = !isBlack;
    });

    // 纵向查找是否有5个连续的相同棋子
    function checkVertical(row, col) {
        let up = 0;
        let dow = 0;
        let count = 1; // 初始化为1，自身也算一颗棋子
        let target = isBlack ? "black" : "white";
        let times = 0;
        while (times < 100) {
            times++;
            // 向上查找
            up++;
            if (circles[row][col - up] && circles[row][col - up] === target) {
                count++;
            }

            // 向下
            dow++;
            if (circles[row][col + dow] && circles[row][col + dow] === target) {
                count++;
            }

            // 如果棋子已经大于一个指定的次数或者棋子不是连续的了，这里当你判断条件第一步是成立的，肯定就是五个连续的棋子了
            if (count >= 5 || (circles[row][col - up] !== target && circles[row][col + dow] !== target)) {
                break;
            }
        }
        return count >= 5;
    }

    // 横向查找是否有五个连续的相同棋子
    function checkHorizontal(row, col) {
        let left = 0;
        let right = 0;
        let count = 1; // 初始化为1，自身也算一颗棋子
        let target = isBlack ? "black" : "white";
        let times = 0;
        while (times < 100) {
            times++;
            // 向上查找
            left++;
            if (circles[row - left][col] && circles[row - left][col] === target) {
                count++;
            }

            // 向下
            right++;
            if (circles[row + right][col] && circles[row + right][col] === target) {
                count++;
            }

            // 如果棋子已经大于一个指定的次数或者棋子不是连续的了，这里当你判断条件第一步是成立的，肯定就是五个连续的棋子了
            if (count >= 5 || (circles[row - left][col] !== target && circles[row + right][col] !== target)) {
                break;
            }
        }
        return count >= 5;
    }

    // 判断从左上-右下的连续
    function checkNW2SE(row, col) {
        let lt = 0;
        let rb = 0;
        let target = isBlack ? "black" : "white";

        let count = 1;
        let times = 0;

        while (times < 100) {
            times++;

            lt++;
            if (circles[row - lt][col - lt] && circles[row - lt][col - lt] === target) {
                count++;
            }

            rb++;
            if (circles[row + rb][col + rb] && circles[row + rb][col + rb] === target) {
                count++;
            }

            if (count >= 5 || (circles[row + rb][col + rb] !== target && circles[row - lt][col - lt] !== target)) {
                break;
            }
        }
        return count >= 5
    }


    // 判断从右上-左下的连续
    function checkNE2SW(row, col) {
        let rt = 0;
        let lb = 0;
        let target = isBlack ? "black" : "white";

        let count = 1;
        let times = 0;

        while (times < 100) {
            times++;

            rt++;
            if (circles[row + rt][col - rt] && circles[row + rt][col - rt] === target) {
                count++;
            }

            lb++;
            if (circles[row - lb][col + lb] && circles[row - lb][col + lb] === target) {
                count++;
            }

            if (count >= 5 || (circles[row + rt][col - rt] !== target && circles[row - lb][col + lb] !== target)) {
                break;
            }
        }
        return count >= 5
    }
</script>